package cn.bird.storm.component;

import cn.bird.storm.annotation.PermitAll;
import cn.bird.storm.model.bo.CollectPathProperties;
import cn.bird.storm.model.bo.RequestMappingBO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 收集项目中的rest 路径
 */
@RequiredArgsConstructor
public class CollectPathComponent implements ApplicationListener<ContextRefreshedEvent> {

    private static String NEED_AUTH = "storm:coll:path:needAuth";
    private static String NO_NEED_AUTH = "storm:coll:noNeedAuth";

    private final CollectPathAdapter collectPathAdapter;
    private final CollectPathProperties collectPathProperties;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        collect(event.getApplicationContext());
    }
    /**
     * 收集项目中的rest 路径
     */
    private void collect(ApplicationContext context) {
        var needAuth = new ArrayList<RequestMappingBO>();
        var noNeedAuth = new ArrayList<RequestMappingBO>();
        var controllers = context.getBeansWithAnnotation(RestController.class);
        //循环所有的controller
        for (Object controller : controllers.values()) {
            RequestMapping controllerRequestMapping
                    = AnnotatedElementUtils.findMergedAnnotation(controller.getClass(), RequestMapping.class);
            //取得 controller 的路径
            var controllerPath = Optional.ofNullable(controllerRequestMapping)
                    .map(RequestMapping::value)
                    .filter(paths -> paths.length > 0)
                    .map(paths -> paths[0])
                    .orElse("");
            //如果 controller 路径不是/开头的，补上/
            if (!controllerPath.startsWith("/")) {
                controllerPath = "/" + controllerPath;
            }
            String className = Optional.ofNullable(controllerRequestMapping).map(RequestMapping::name).orElse("");
            //判断controller是否有 PermitAll 注解
            PermitAll controllerPermitAll = AnnotatedElementUtils.findMergedAnnotation(controller.getClass(), PermitAll.class);
            //如果 controller 路径不为空并且有 PermitAll 注解，直接跳过
            if (StrUtil.isNotEmpty(controllerPath) && controllerPermitAll != null) {
                RequestMappingBO requestMappingBO = new RequestMappingBO();
                requestMappingBO.setPath(controllerPath + "/**");
                requestMappingBO.setName(className);
                requestMappingBO.setParentName(className);
                requestMappingBO.setModel(collectPathProperties.getName());
                noNeedAuth.add(requestMappingBO);
                continue;
            }
            boolean classPermitAll = controllerPermitAll != null;
            for (Method method : ReflectUtil.getMethods(controller.getClass())) {
                RequestMapping methodRequestMapping
                        = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
                if (methodRequestMapping == null) {
                    continue;
                }

                var methodPath = Optional.of(methodRequestMapping)
                        .map(RequestMapping::value)
                        .filter(paths -> paths.length > 0)
                        .map(paths -> paths[0])
                        .orElse("");
                if (StrUtil.isNotBlank(methodPath)&&!methodPath.startsWith("/")) {
                    methodPath = "/" + methodPath;
                }
                var path = controllerPath + methodPath;
                //封装成 RequestMappingBO
                RequestMappingBO requestMappingBO = new RequestMappingBO();
                requestMappingBO.setPath(path);
                requestMappingBO.setName(className + "-" + methodRequestMapping.name());
                requestMappingBO.setParentName(className);
                requestMappingBO.setModel(collectPathProperties.getName());
                requestMappingBO.setMethod(Arrays.stream(methodRequestMapping.method())
                        .map(RequestMethod::name)
                        .collect(Collectors.toList())
                );
                var notNeedAuth = AnnotatedElementUtils.findMergedAnnotation(method, PermitAll.class);
                if (notNeedAuth != null|| classPermitAll) {
                    noNeedAuth.add(requestMappingBO);
                } else {
                    needAuth.add(requestMappingBO);
                }
            }
        }
        if (CollUtil.isNotEmpty(needAuth)) {
            List<RequestMappingBO> alreadyBos = collectPathAdapter.needAuthGet(NEED_AUTH);
            alreadyBos.addAll(needAuth);
            collectPathAdapter.needAuthSave(NEED_AUTH, alreadyBos);
        }
        if (CollUtil.isNotEmpty(noNeedAuth)) {
            List<RequestMappingBO> alreadyBos = collectPathAdapter.noNeedAuthGet(NO_NEED_AUTH);
            alreadyBos.addAll(noNeedAuth);
            collectPathAdapter.noNeedAuthSave(NO_NEED_AUTH, alreadyBos);
        }
    }
    /**
     * 不需要授权的访问地址
     */
    public List<RequestMappingBO> noNeedAuth(){
       return collectPathAdapter.noNeedAuthGet(NO_NEED_AUTH);
    }

    /**
     * 需要授权的访问地址
     */
    public List<RequestMappingBO> needAuth(){
        return collectPathAdapter.noNeedAuthGet(NEED_AUTH);
    }
}
